package com.example.service;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.common.Constants;
import com.example.common.HttpStatusEnum;
import com.example.config.ConfigTableValueConfig;
import com.example.entity.ResponseData;
import com.example.entity.TableUser;
import com.example.mapper.DoctorMapper;
import com.example.mapper.EnterpriseMapper;
import com.example.mapper.UserMapper;
import com.example.pojo.Doctor;
import com.example.pojo.Enterprise;
import com.example.pojo.User;
import com.example.util.*;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户信息表(User)表服务实现类
 *
 * @email: pengyujun53@163.com
 * @author: peng_YuJun
 * @date: 2024/01/17
 * @time: 23:13
 */
@Slf4j
@Service
public class UserService {
    // mapper对象
    @Resource
    private UserMapper userMapper;
    @Resource
    private EnterpriseMapper enterpriseMapper;
    @Resource
    private DoctorMapper doctorMapper;
    // 微信登录util
    @Resource
    private WeChatUtil weChatUtil;
    // 榛子云短信服务
    @Resource
    private ZhenziUtil zhenziUtil;
    // 系统配置参数
    @Resource
    private ConfigTableValueConfig configValue;

    /**
     * 分页查询
     *
     * @param currentPage
     * @param pageSize
     * @param user        筛选条件
     * @return
     */
    public ResponseData getByPage(Integer currentPage, Integer pageSize, User user) {
        //查询
        IPage ipage = new Page(currentPage, pageSize);
        userMapper.mySelectPage(ipage, user);
        //若当前页码大于总页面数
        if (currentPage > ipage.getPages()) {
            ipage = new Page(ipage.getPages(), pageSize);
            userMapper.mySelectPage(ipage, user);
        }
        if (ipage.getTotal() <= 0) {
            return new ResponseData(HttpStatusEnum.DATA_NOT_EXIST.getCode(), HttpStatusEnum.DATA_NOT_EXIST.getMessage());
        }
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), ipage);
    }

    /**
     * 根据ID查询信息
     *
     * @param id 主键
     * @return 单条数据
     */
    public ResponseData findById(Long id) {
        User user = userMapper.selectById(id);
        if (user == null || user.getId() == null) {
            return new ResponseData(HttpStatusEnum.DATA_NOT_EXIST.getCode(), HttpStatusEnum.DATA_NOT_EXIST.getMessage());
        }
        //返回结果
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), user);
    }

    /**
     * 新增数据
     *
     * @param user 实体
     * @return 新增结果
     */
    public ResponseData add(User user) {
        //先查询，该手机号是否已经注册
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.like(StringUtils.hasText(user.getPhone()), User::getPhone, user.getPhone());
        Long sum = userMapper.selectCount(lqw);
        if (sum > 0)
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "新增失败，该手机号已注册");
        //盐
        String salt = RandomUtil.randomString(6);
        user.setSalt(salt);
        //加密密码
        String md5Pwd = SecureUtil.md5(user.getPwd() + salt);
        user.setPwd(md5Pwd);
        //账户名为空时，自动赋值
        user.setName(StringUtils.hasText(user.getName()) ? user.getName() : "用户" + user.getPhone());
        //开始添加新账号
        int insertResult = userMapper.insert(user);
        if (insertResult > 0) {
            try {
                //生成头像
                user.setAvatar(configValue.getAvatarNetUrl() + Constants.FORWARD_SLASH +
                        AvatarHelper.generateImg(user.getName(), configValue.getAvatarStorePath(), String.valueOf(user.getId()), 30));
                userMapper.updateById(user);
            } catch (IOException e) {
                log.error(ExceptionUtil.getStackTraceInfo(e));
            }
            return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), "新增成功");
        }
        return new ResponseData(HttpStatusEnum.ERROR.getCode(), "新增失败，请稍后再试");
    }

    /**
     * 更新数据
     *
     * @param user 实体
     * @return 更新结果
     */
    public ResponseData update(User user) {
        //判断修改用户是否存在
        User queryUser = userMapper.selectById(user.getId());
        if (queryUser == null){
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "修改失败，修改用户不存在");
        }
        //判断密码有没有修改
        if (StringUtils.hasText(user.getPwd())){
            String checkPwd = SecureUtil.md5(user.getPwd() + queryUser.getSalt());
            if (!checkPwd.equals(queryUser.getPwd())){
                //盐
                String salt = RandomUtil.randomString(6);
                user.setSalt(salt);
                //加密密码
                String md5Pwd = SecureUtil.md5(user.getPwd() + salt);
                user.setPwd(md5Pwd);
            }
        }
        //判断手机号有没有修改
        if (StringUtils.hasText(user.getPhone())){
            if (!user.getPhone().equals(queryUser.getPhone())){
                LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
                lqw.eq(User::getPhone,user.getPhone());
                Long sum = userMapper.selectCount(lqw);
                if (sum > 0)
                    return new ResponseData(HttpStatusEnum.ERROR.getCode(), "修改失败，修改的手机号已注册");
            }
        }
        //更新
        if (userMapper.updateById(user) > 0) {
            return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage());
        }
        return new ResponseData(HttpStatusEnum.ERROR.getCode(), "修改失败，请稍后再试");
    }

    /**
     * 删除数据
     *
     * @param id 主键
     * @return
     */
    public ResponseData delete(Long id) {
        if (userMapper.deleteById(id) > 0) {
            //返回成功响应
            return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage());
        }
        return new ResponseData(HttpStatusEnum.ERROR.getCode(), "删除失败，请稍后再试");
    }

    /**
     * 批量删除
     *
     * @param idList
     * @return
     */
    public ResponseData deleteBatch(List<Long> idList) {
        if (userMapper.deleteBatchIds(idList) > 0) {
            //返回成功响应
            return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage());
        }
        return new ResponseData(HttpStatusEnum.ERROR.getCode(), "删除失败，请稍后再试");
    }

    /**
     * 账号密码登录
     *
     * @param phone
     * @param pwd
     * @return
     */
    public ResponseData loginUser(String phone, String pwd) {
        // 根据账号查询用户
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getPhone, phone);
        List<User> users = userMapper.selectList(lqw);
        if (users.isEmpty()) {
            return new ResponseData(HttpStatusEnum.DATA_NOT_EXIST.getCode(), "账户不存在，请检查输入");
        }
        // 查询到多个用户，返回：账号异常，请联系管理员
        if (users.size() > 1) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "账号异常，请联系管理员");
        }
        // 查询到一个用户
        User u = users.get(0);
        // 若用户被禁用，不允许登录
        if (u.getDeleted() == 1) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "账户已被禁用，无法登录");
        }
        //验证密码
        String loginPwd = SecureUtil.md5(pwd + u.getSalt());
        if (!loginPwd.equals(u.getPwd())) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "密码错误，请重新输入");
        }
        //获取JWT
        String jwt = JwtUtil.generatorToken(u.getId().toString());
        // 获取所属机构名称
        String entName = null;
        if (StringUtils.hasText(u.getEntCode())){
            LambdaQueryWrapper<Enterprise> entLqw = new LambdaQueryWrapper<>();
            entLqw.eq(Enterprise::getCode, u.getEntCode());
            // 查询
            Enterprise enterprise = enterpriseMapper.selectOne(entLqw);
            entName = enterprise.getTitle();
        }
        // 如果是医生需要获取签名
        String sign = null;
        if (u.getCode().contains("dr")){
            LambdaQueryWrapper<Doctor> drLqw = new LambdaQueryWrapper<>();
            drLqw.eq(Doctor::getUid, u.getId());
            // 查询
            Doctor doctor = doctorMapper.selectOne(drLqw);
            sign = doctor.getSign();
        }
        //返回成功结果
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("token", jwt);
        resultMap.put("id", u.getId());
        resultMap.put("avatar", u.getAvatar());
        resultMap.put("name", u.getName());
        resultMap.put("phone", u.getPhone());
        resultMap.put("ruleCode", u.getRuleCode());
        resultMap.put("entName", entName);
        resultMap.put("sign", sign);
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), "登录成功", resultMap);
    }

    /**
     * 微信小程序用户登录
     *
     * @param code
     */
    public ResponseData loginUserAtWMP(String code) {
        // 获取openid。通过openid登录
        String openId = weChatUtil.getOpenId(code);
        if (!StringUtils.hasText(openId)) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "系统异常，请联系管理员");
        }
        // 根据openid查询用户
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getOpenId, openId);
        List<User> users = userMapper.selectList(lqw);
        if (users.isEmpty()) {
            return new ResponseData(HttpStatusEnum.DATA_NOT_EXIST.getCode(), "微信未绑定账户，请先通过账户登录");
        }
        // 查询到多个用户，返回：账号异常，请联系管理员
        if (users.size() > 1) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "账号异常，请联系管理员");
        }
        // 查询到一个用户
        User u = users.get(0);
        // 若用户被禁用，不允许登录
        if (u.getDeleted() == 1) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "账户已被禁用，无法登录");
        }
        //获取JWT
        String jwt = JwtUtil.generatorToken(u.getId().toString());
        // 获取所属机构名称
        String entName = null;
        if (StringUtils.hasText(u.getEntCode())){
            LambdaQueryWrapper<Enterprise> entLqw = new LambdaQueryWrapper<>();
            entLqw.eq(Enterprise::getCode, u.getEntCode());
            // 查询
            Enterprise enterprise = enterpriseMapper.selectOne(entLqw);
            entName = enterprise.getTitle();
        }
        //返回成功结果
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("token", jwt);
        resultMap.put("id", u.getId());
        resultMap.put("avatar", u.getAvatar());
        resultMap.put("name", u.getName());
        resultMap.put("phone", u.getPhone());
        resultMap.put("entName", entName);
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), "登录成功", resultMap);
    }

    /**
     * 获取短信验证码
     *
     * @param phone
     * @param request
     * @return
     */
    public ResponseData getMsgCode(String phone, HttpServletRequest request) {
        //验证该手机号是否已注册
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("phone", phone);
        Long sum = userMapper.selectCount(userQueryWrapper);
        if (sum == 0) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "账户不存在，请检查账号输入");
        }
        //开始生成短信验证码返回
        try {
            //随机生成验证码
            String random = zhenziUtil.printRandom();
            //将验证码通过榛子云接口发送至手机
            String result = zhenziUtil.sendMessage(random, phone);
            JSONObject json = JSONUtil.parseObj(result);
            if (Integer.parseInt(json.get("code").toString()) != 0) {//发送短信失败
                return new ResponseData(HttpStatusEnum.ERROR.getCode(), "验证码发送失败，请稍后重试");
            }
            //将验证码存到session中,同时存入创建时间
            json = new JSONObject();
            json.set("phone", phone);
            json.set("code", random);
            json.set("createTime", System.currentTimeMillis());
            // 将验证码存入SESSION
            request.getServletContext().setAttribute("msgCodeObj", json);
        } catch (Exception e) {
            log.error("短信验证码发送抛出异常：", e);
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "验证码发送失败，请稍后重试");
        }
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), "验证码发送成功，请留意手机信息");
    }

    /**
     * 短信验证码登录
     *
     * @param phone
     * @param msgCode
     * @return
     */
    public ResponseData msgCodeLogin(String phone, String msgCode, HttpServletRequest request) {
        JSONObject msgCodeObj = (JSONObject) request.getServletContext().getAttribute("msgCodeObj");
        //会话中无验证码实体时
        if (msgCodeObj == null) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "验证码已失效，请重新发送");
        }
        //判断验证码是否过期
        long nowTime = System.currentTimeMillis();
        long countTime = nowTime - (long) msgCodeObj.get("createTime");
        if (countTime > 5 * 60 * 1000) {
            request.getServletContext().removeAttribute("msgCodeObj");
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "验证码已过期，请重新发送");
        }
        //判断验证码是否正确，正确则可开始登录
        if (msgCode.equals(msgCodeObj.get("code"))) {
            //正确，开始注册
            //先查询，该手机号是否已经注册
            LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
            lqw.eq(User::getPhone, phone);
            List<User> users = userMapper.selectList(lqw);
            // 查询到多个用户，返回：账号异常，请联系管理员
            if (users.size() > 1) {
                return new ResponseData(HttpStatusEnum.ERROR.getCode(), "账号异常，请联系管理员");
            }
            // 查询到一个用户
            User u = users.get(0);
            // 若用户被禁用，不允许登录
            if (u.getDeleted() == 1) {
                return new ResponseData(HttpStatusEnum.ERROR.getCode(), "账户已被禁用，无法登录");
            }
            //获取JWT
            String jwt = JwtUtil.generatorToken(u.getId().toString());
            // 获取所属机构名称
            String entName = null;
            if (StringUtils.hasText(u.getEntCode())){
                LambdaQueryWrapper<Enterprise> entLqw = new LambdaQueryWrapper<>();
                entLqw.eq(Enterprise::getCode, u.getEntCode());
                // 查询
                Enterprise enterprise = enterpriseMapper.selectOne(entLqw);
                entName = enterprise.getTitle();
            }
            //返回成功结果
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", jwt);
            resultMap.put("id", u.getId());
            resultMap.put("avatar", u.getAvatar());
            resultMap.put("name", u.getName());
            resultMap.put("phone", u.getPhone());
            resultMap.put("entName", entName);
            return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), "登录成功", resultMap);
        } else {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "验证码错误，请重新输入");
        }
    }

    /**
     * 修改密码
     *
     * @param phone
     * @param newPwd
     * @param msgCode
     * @return
     */
    public ResponseData resetUserPwdByMsg(String phone, String newPwd, String msgCode, HttpServletRequest request) {
        JSONObject msgCodeObj = (JSONObject) request.getServletContext().getAttribute("msgCodeObj");
        //会话中无验证码实体时
        if (msgCodeObj == null) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "验证码已失效，请重新发送");
        }
        //判断验证码是否过期
        long nowTime = System.currentTimeMillis();
        long countTime = nowTime - (long) msgCodeObj.get("createTime");
        if (countTime > 5 * 60 * 1000) {
            request.getServletContext().removeAttribute("msgCodeObj");
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "验证码已过期，请重新发送");
        }
        //判断验证码是否正确，正确则可开始修改密码
        if (!msgCode.equals(msgCodeObj.get("code"))) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "验证码错误，请重新输入");
        }
        //正确，开始验证修改
        //先查询，该手机号是否已经注册
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(User::getPhone, phone);
        List<User> users = userMapper.selectList(lqw);
        // 查询到多个用户，返回：账号异常，请联系管理员
        if (users.size() > 1) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "账号异常，请联系管理员");
        }
        // 查询到一个用户
        User u = users.get(0);
        // 开始修改密码
        // 盐
        String salt = RandomUtil.randomString(6);
        // 加密密码
        String md5Pwd = SecureUtil.md5(newPwd + salt);
        u.setSalt(salt);
        u.setPwd(md5Pwd);
        // 更新数据
        int result = userMapper.updateById(u);
        if (result == 0) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "修改失败，请稍后重试");
        }
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), "修改成功，新密码已生效");
    }

    /**
     * 修改密码
     * @param oldPwd
     * @param newPwd
     * @param id
     * @return
     */
    public ResponseData resetUserPwd(String oldPwd, String newPwd, Long id) {
        // 先查询
        User u = userMapper.selectById(id);
        // 查询不到
        if (u == null || u.getId() == null) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "账号不存在，修改失败");
        }
        // 比对旧密码是否一致
        String oldMd5Pwd = SecureUtil.md5(oldPwd + u.getSalt());
        if (!oldMd5Pwd.equals(u.getPwd())){
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "旧密码不一致，修改失败");
        }
        // 开始修改密码
        // 盐
        String salt = RandomUtil.randomString(6);
        // 加密密码
        String md5Pwd = SecureUtil.md5(newPwd + salt);
        u.setSalt(salt);
        u.setPwd(md5Pwd);
        // 更新数据
        int result = userMapper.updateById(u);
        if (result == 0) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "修改失败，请稍后重试");
        }
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), "修改成功，新密码已生效");
    }

    /**
     * 修改密码
     * @param userId
     * @param oldPwd
     * @param newPwd
     * @return
     */
    public ResponseData updatePwd(Integer userId, String oldPwd, String newPwd) {
        User user = userMapper.selectById(userId);
        if (user == null || user.getId() == null){
            return new ResponseData(HttpStatusEnum.ERROR.getCode(),"修改失败，该用户不存在");
        }
        if (SecureUtil.md5(oldPwd+user.getSalt()).equals(user.getPwd())){
            //盐
            String salt = RandomUtil.randomString(6);
            //用户新修改的密码和盐加密
            String newMd5Pwd = SecureUtil.md5(newPwd + salt);
            //修改用户信息
            user.setSalt(salt);
            user.setPwd(newMd5Pwd);

            if (userMapper.updateById(user)>0){
                return new ResponseData(HttpStatusEnum.SUCCESS.getCode(),"修改成功");
            }else {
                return new ResponseData(HttpStatusEnum.ERROR.getCode(),"修改失败，请稍后再试");
            }
        }else {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(),"修改失败，旧密码匹配不符");
        }
    }

    /**
     * 绑定微信openid
     * @param code
     * @param request
     * @return
     */
    public ResponseData bindAccountToWX(String code, HttpServletRequest request) {
        // 获取openid。通过openid登录
        String openId = weChatUtil.getOpenId(code);
        if (!StringUtils.hasText(openId)) {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(), "系统异常，请联系管理员");
        }
        // 从token中获取用户id
        String token = request.getHeader("Authorization"); //取出token
        Claims claims = JwtUtil.parsePayload(token);  //解析token
        if (claims == null) { //检验token
            return new ResponseData(HttpStatusEnum.LOGIN_EXPIRED.getCode(), HttpStatusEnum.LOGIN_EXPIRED.getMessage());
        }
        Integer uid = Integer.parseInt((String) claims.get("uid"));
        // 先通过uid获取用户数据
        User user = userMapper.selectById(uid);
        if (user == null || user.getId() == null) {
            return new ResponseData(HttpStatusEnum.DATA_NOT_EXIST.getCode(), HttpStatusEnum.DATA_NOT_EXIST.getMessage());
        }
        // 开始更新
        user.setOpenId(openId);
        if (userMapper.updateById(user)>0){
            return new ResponseData(HttpStatusEnum.SUCCESS.getCode(),"绑定成功");
        }else {
            return new ResponseData(HttpStatusEnum.ERROR.getCode(),"绑定失败，请稍后再试");
        }
    }

    /**
     * 根据机构编码和名字查询用户
     */
    public ResponseData findByEntAndName(String entCode, String name) {
        User user = new User();
        user.setEntCode(entCode);
        user.setName(name);
        List<TableUser> tableUsers = userMapper.mySelectList(user);
        if (tableUsers == null || tableUsers.isEmpty()) {
            return new ResponseData(HttpStatusEnum.DATA_NOT_EXIST.getCode(), HttpStatusEnum.DATA_NOT_EXIST.getMessage());
        }
        //返回结果
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), tableUsers);
    }

    /**
     * 根据id查询用户的前端显示数据
     * @param id
     * @return
     */
    public ResponseData findTableUserById(Long id) {
        User user = new User();
        user.setId(id);
        List<TableUser> tableUsers = userMapper.mySelectList(user);
        if (tableUsers == null || tableUsers.isEmpty()) {
            return new ResponseData(HttpStatusEnum.DATA_NOT_EXIST.getCode(), HttpStatusEnum.DATA_NOT_EXIST.getMessage());
        }
        //返回结果
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), tableUsers.get(0));
    }

    /**
     * 统计不同角色用户数
     * @return
     */
    public ResponseData countRole() {
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        Map<String, Object> result = new HashMap<>();
        //学生
        lqw.like(User::getCode, "stu");
        result.put("stuNum", userMapper.selectCount(lqw));
        lqw.clear();
        //校医
        lqw.like(User::getCode, "dr");
        result.put("drNum", userMapper.selectCount(lqw));
        lqw.clear();
        //管理员
        lqw.like(User::getCode, "manage");
        result.put("manageNum", userMapper.selectCount(lqw));
        lqw.clear();
        //返回查询结果
        return new ResponseData(HttpStatusEnum.SUCCESS.getCode(), HttpStatusEnum.SUCCESS.getMessage(), result);
    }
}
